package com.lock.redisLocks.ledixbinary;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lock.redisLocks.RedisHelper;
import com.lock.redisLocks.RedisHelper.JedisPoolWraper;
import com.lock.redisLocks.RedisHelper.ProviderConfigType;
import com.lock.redisLocks.RedisHelper.RedisConfigType;

import io.lettuce.core.AbstractRedisClient;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
import io.lettuce.core.codec.ByteArrayCodec;

/**
 * ERP中有部分用字节码操作数据的操作, 这个操作, 在jedis和lettuce之间不兼容,
 * 因此写一个专门的Lettuce工具
 * 
 * @author haitao.wang
 *
 */

public class LedixBinaryHelper {
	private final static Logger log = LoggerFactory.getLogger(LedixBinaryHelper.class);
	private static Map<String, JedisPoolWraper<?, Void, AbstractRedisClient>> jedixBinaryPools = new ConcurrentHashMap<>();
	private final static ReentrantReadWriteLock rwLockInit = new ReentrantReadWriteLock();

	/*
	 * 这里从map里直接获取 LedixBinary对象
	 */
	@SuppressWarnings("rawtypes")
	public static void intiLedixBinary(String poolName) {
		RedisHelper.assistCheckState(!RedisHelper.isShutdown(), "JedisHelper is shutdown");
		RedisHelper.assistCheckArgument(StringUtils.isNotBlank(poolName), "PoolName should not be empty");

		JedisPoolWraper jedisPoolWraper = RedisHelper.getJedisPoolWraper(poolName);
		RedisHelper.assistCheckState(jedisPoolWraper != null, "Redis Resource " + poolName + " is null");

		ProviderConfigType providerConfigType = jedisPoolWraper.getProvider();
		RedisHelper.assistCheckState(ProviderConfigType.LETTUCE.equals(providerConfigType), "Only Support LETTUCE Provider Operation, pool[" + poolName + "] provider is illegal");

		RedisConfigType redisConfigType = jedisPoolWraper.getType();
		if (RedisConfigType.SINGLE.equals(redisConfigType)) {
			RedisClient redisClient = (RedisClient) jedisPoolWraper.getAppendObj();
			StatefulRedisConnection<byte[], byte[]> conn = redisClient.connect(ByteArrayCodec.INSTANCE);
			jedixBinaryPools.put(poolName, new JedisPoolWraper<StatefulRedisConnection<byte[], byte[]>, Void, AbstractRedisClient>(poolName, conn, jedisPoolWraper.isUsePool(), redisConfigType, providerConfigType, null, null, redisClient));

		} else if (RedisConfigType.CLUSTER.equals(redisConfigType)) {
			RedisClusterClient clusterClient = (RedisClusterClient) jedisPoolWraper.getAppendObj();
			StatefulRedisClusterConnection<byte[], byte[]> conn = clusterClient.connect(ByteArrayCodec.INSTANCE);
			jedixBinaryPools.put(poolName, new JedisPoolWraper<StatefulRedisClusterConnection<byte[], byte[]>, Void, AbstractRedisClient>(poolName, conn, jedisPoolWraper.isUsePool(), redisConfigType, providerConfigType, null, null, clusterClient));

		} else {
			throw new RuntimeException("ILLegal RedisConfigType:" + redisConfigType);
		}
	}

	/**
	 * 获取LedixBinary
	 * 
	 * @return
	 */
	public static LedixBinary getLedixBinary() {
		return getLedixBinary(RedisHelper.getDefaultPoolName());
	}

	@SuppressWarnings("unchecked")
	public static LedixBinary getLedixBinary(String name) {

		RedisHelper.assistCheckState(!RedisHelper.isShutdown(), "JedisHelper is shutdown");
		RedisHelper.assistCheckArgument(StringUtils.isNotBlank(name), "PoolName should not be empty");

		JedisPoolWraper<?, Void, AbstractRedisClient> poolJedisPoolWraper = jedixBinaryPools.get(name);

		if (poolJedisPoolWraper == null) {

			if (!RedisHelper.getPoolNames().contains(name)) {
				throw new RuntimeException("Pool[" + name + "] is null");
			} else {
				try {
					rwLockInit.writeLock().lock();
					// 初始化二进制操作连接池
					intiLedixBinary(name);
					System.err.println("init pool:" + name);
					poolJedisPoolWraper = jedixBinaryPools.get(name);
				} finally {
					rwLockInit.writeLock().unlock();
				}
			}
		}

		LedixBinary jedixBinary = null;
		if (RedisConfigType.SINGLE.equals(poolJedisPoolWraper.getType())) {// LETTUCE单机
			StatefulRedisConnection<byte[], byte[]> conn = (StatefulRedisConnection<byte[], byte[]>) poolJedisPoolWraper.getPool();

			RedisCommands<byte[], byte[]> syncCmd = conn.sync();
			jedixBinary = LedixBinaryWrapping.<LedixBinary, RedisCommands<byte[], byte[]>>wrapLedixBinary(syncCmd, poolJedisPoolWraper.getType(), poolJedisPoolWraper.getProvider());

		} else if (RedisConfigType.CLUSTER.equals(poolJedisPoolWraper.getType())) {// LETTUCE集群
			StatefulRedisClusterConnection<byte[], byte[]> conn = (StatefulRedisClusterConnection<byte[], byte[]>) poolJedisPoolWraper.getPool();
			// RedisClusterCommands
			RedisAdvancedClusterCommands<byte[], byte[]> syncCmd = conn.sync();
			jedixBinary = LedixBinaryWrapping.<LedixBinary, RedisAdvancedClusterCommands<byte[], byte[]>>wrapLedixBinary(syncCmd, poolJedisPoolWraper.getType(), poolJedisPoolWraper.getProvider());
		}

		return jedixBinary;

	}

	public static JedisPoolWraper<?, Void, AbstractRedisClient> getJedisPoolWraper(String name) {
		RedisHelper.assistCheckState(!RedisHelper.isShutdown(), "JedisHelper is shutdown");
		RedisHelper.assistCheckArgument(StringUtils.isNotBlank(name), "PoolName should not be empty");
		return jedixBinaryPools.get(name);
	}

	@SuppressWarnings("unchecked")
	public static synchronized void shutdown() {
		try {
			Set<String> keySet = jedixBinaryPools.keySet();
			String[] keyArray = new String[keySet.size()];
			int idx = 0;
			for (String tmpKey : keySet) {
				keyArray[idx++] = tmpKey;
			}
			for (String tmpKey : keyArray) {
				String poolName = tmpKey;
				log.warn("shutdown pool[{}]...", poolName);
				JedisPoolWraper<?, Void, AbstractRedisClient> jedisPoolWraper = jedixBinaryPools.remove(poolName);
				if (jedisPoolWraper != null) {
					try {
						if (ProviderConfigType.LETTUCE.equals(jedisPoolWraper.getProvider())) {
							if (RedisConfigType.SINGLE.equals(jedisPoolWraper.getType())) {// LETTUCE单机
								StatefulRedisConnection<byte[], byte[]> conn = (StatefulRedisConnection<byte[], byte[]>) jedisPoolWraper.getPool();
								conn.close();
								// 这里的Client由RedisHelper操作关闭, 这里不再关闭
								// AbstractRedisClient lettuceRedisClient = jedisPoolWraper.getAppendObj();
								// lettuceRedisClient.shutdown();

							} else if (RedisConfigType.CLUSTER.equals(jedisPoolWraper.getType())) {// LETTUCE集群
								StatefulRedisClusterConnection<byte[], byte[]> conn = (StatefulRedisClusterConnection<byte[], byte[]>) jedisPoolWraper.getPool();
								conn.close();
								// AbstractRedisClient clusterClient = jedisPoolWraper.getAppendObj();
								// clusterClient.shutdown();
							}
						}
					} catch (Throwable e) {
						log.error("Close Pool Error key={}", poolName, e);
					}
				}
				jedisPoolWraper = null;
			}
		} finally {
			jedixBinaryPools = null;
		}
	}

}
